/*
 * This file is part of Cadmium.
 * Copyright (C) 2007-2010 Xavier Clerc.
 *
 * Cadmium is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Cadmium is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.x9c.cadmium.primitives.cadmiumjdbc;

import java.sql.Connection;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.List;

import fr.x9c.cadmium.kernel.Block;
import fr.x9c.cadmium.kernel.CodeRunner;
import fr.x9c.cadmium.kernel.Fail;
import fr.x9c.cadmium.kernel.Primitive;
import fr.x9c.cadmium.kernel.PrimitiveProvider;
import fr.x9c.cadmium.kernel.Value;
import fr.x9c.cadmium.primitives.cadmium.Cadmium;

/**
 * This class provides the primitives related to the <tt>java.sql.Connection</tt> class.
 *
 * @author <a href="mailto:cadmium@x9c.fr">Xavier Clerc</a>
 * @version 1.1
 * @since 1.1
 */
@PrimitiveProvider
public final class Connections {

    /**
     * No instance of this class.
     */
    private Connections() {
    } // end empty constructor

    /**
     * Clears the warnings for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_clear_warnings(final CodeRunner ctxt,
                                                              final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.clearWarnings();
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_clear_warnings(CodeRunner, Value)'

    /**
     * Closes the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_close(final CodeRunner ctxt,
                                                     final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.close();
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_close(CodeRunner, Value)'

    /**
     * Commits the changes for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_commit(final CodeRunner ctxt,
                                                      final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.commit();
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_commit(CodeRunner, Value)'

    /**
     * Creates an array.
     * @param ctxt context
     * @param connection connection
     * @param typeName SQL name for the elements
     * @param elements array elements
     * @return an array containing the passed elements
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_create_array_of(final CodeRunner ctxt,
                                                               final Value connection,
                                                               final Value typeName,
                                                               final Value elements)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            final List<Object> elems = new ArrayList<Object>();
            Value list = elements;
            while (list != Value.EMPTY_LIST) {
                final Block b = list.asBlock();
                elems.add(b.get(0).asBlock().asCustom());
                list = b.get(1);
            } // end while
            return Cadmium.createObject(c.createArrayOf(typeName.asBlock().asString(),
                                                        elems.toArray()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_create_array_of(CodeRunner, Value, Value, Value)'

    /**
     * Creates a blob.
     * @param ctxt context
     * @param connection connection
     * @return a new blob
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_create_blob(final CodeRunner ctxt,
                                                           final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.createBlob());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_create_blob(CodeRunner, Value)'

    /**
     * Creates a clob.
     * @param ctxt context
     * @param connection connection
     * @return a new clob
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_create_clob(final CodeRunner ctxt,
                                                           final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.createClob());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_create_clob(CodeRunner, Value)'

    /**
     * Creates a nclob.
     * @param ctxt context
     * @param connection connection
     * @return a new nclob
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_create_nclob(final CodeRunner ctxt,
                                                            final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.createNClob());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_create_nclob(CodeRunner, Value)'

    /**
     * Creates a SQL XML.
     * @param ctxt context
     * @param connection connection
     * @return a new SQL XML
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_create_sqlxml(final CodeRunner ctxt,
                                                             final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.createSQLXML());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_create_sqlxml(CodeRunner, Value)'

    /**
     * Creates a statement.
     * @param ctxt context
     * @param connection connection
     * @return a new statement
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_create_statement(final CodeRunner ctxt,
                                                                final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.createStatement());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_create_statement(CodeRunner, Value)'

    /**
     * Creates a statement.
     * @param ctxt context
     * @param connection connection
     * @param type result set type
     * @param conc result set concurrency
     * @return a new statement
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_create_statement_type_conc(final CodeRunner ctxt,
                                                                          final Value connection,
                                                                          final Value type,
                                                                          final Value conc)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.createStatement(Misc.decodeResultSetType(type),
                                                          Misc.decodeResultSetConcurrency(conc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_create_statement_type_conc(CodeRunner, Value, Value, Value)'

    /**
     * Creates a statement.
     * @param ctxt context
     * @param connection connection
     * @param type result set type
     * @param conc result set concurrency
     * @param hold result set holdability
     * @return a new statement
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_create_statement_type_conc_hold(final CodeRunner ctxt,
                                                                               final Value connection,
                                                                               final Value type,
                                                                               final Value conc,
                                                                               final Value hold)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.createStatement(Misc.decodeResultSetType(type),
                                                          Misc.decodeResultSetConcurrency(conc),
                                                          Misc.decodeResultSetHoldability(hold)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_create_statement_type_conc_hold(CodeRunner, Value, Value, Value, Value)'

    /**
     * Creates a structure.
     * @param ctxt context
     * @param connection connection
     * @param typeName SQL name for the type of the structure
     * @param attributes elements for the structure
     * @return a new structure containing the passed elements
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_create_struct(final CodeRunner ctxt,
                                                             final Value connection,
                                                             final Value typeName,
                                                             final Value attributes)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            final List<Object> attrs = new ArrayList<Object>();
            Value list = attributes;
            while (list != Value.EMPTY_LIST) {
                final Block b = list.asBlock();
                attrs.add(b.get(0).asBlock().asCustom());
                list = b.get(1);
            } // end while
            return Cadmium.createObject(c.createStruct(typeName.asBlock().asString(),
                                                       attrs.toArray()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_create_struct(CodeRunner, Value, Value, Value)'

    /**
     * Tests whether the passed connection has auto-commit mode enabled.
     * @param ctxt context
     * @param connection connection
     * @return <tt>true</tt> if the passed connection has auto-commit mode enabled,
     *         <tt>false</tt> otherwise
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_get_auto_commit(final CodeRunner ctxt,
                                                               final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return c.getAutoCommit() ? Value.TRUE : Value.FALSE;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_get_auto_commit(CodeRunner, Value)'

    /**
     * Returns the catalog name of the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return the catalog name of the passed connection
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_get_catalog(final CodeRunner ctxt,
                                                           final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            final Block res = Block.createString(c.getCatalog());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_get_catalog(CodeRunner, Value)'

    /**
     * Returns the client info properties for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return the client info properties for the passed connection
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_get_client_infos(final CodeRunner ctxt,
                                                                final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Misc.encodeProperties(c.getClientInfo());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_get_client_infos(CodeRunner, Value)'

    /**
     * Returns the value of a client info property for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param name property name
     * @return the value of a client info property for the passed connection
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_get_client_info(final CodeRunner ctxt,
                                                               final Value connection,
                                                               final Value name)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            final Block res = Block.createString(c.getClientInfo(name.asBlock().asString()));
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_get_client_info(CodeRunner, Value, Value)'

    /**
     * Returns the holdability for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return the holdability for the passed connection
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_get_holdability(final CodeRunner ctxt,
                                                               final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Misc.encodeResultSetHoldability(c.getHoldability());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_get_holdability(CodeRunner, Value)'

    /**
     * Returns the metadata for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return the metadata for the passed connection
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_get_meta_data(final CodeRunner ctxt,
                                                             final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.getMetaData());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_get_meta_data(CodeRunner, Value)'

    /**
     * Returns the transaction isolation for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return the transaction isolation for the passed connection
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_get_transaction_isolation(final CodeRunner ctxt,
                                                                         final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Misc.encodeTransactionIsolation(c.getTransactionIsolation());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_get_transaction_isolation(CodeRunner, Value)'

    /**
     * Returns the list of warnings for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return the list of warnings for the passed connection
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_get_warnings(final CodeRunner ctxt,
                                                            final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Misc.encodeSQLWarnings(c.getWarnings());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_get_warnings(CodeRunner, Value)'

    /**
     * Tests whether the passed connection is closed.
     * @param ctxt context
     * @param connection connection
     * @return <tt>true</tt> if the connection is closed,
     *         <tt>false</tt> otherwise
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_is_closed(final CodeRunner ctxt,
                                                         final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return c.isClosed() ? Value.TRUE : Value.FALSE;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_is_closed(CodeRunner, Value)'

    /**
     * Tests whether the passed connection is read only.
     * @param ctxt context
     * @param connection connection
     * @return <tt>true</tt> if the connection is read only,
     *         <tt>false</tt> otherwise
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_is_read_only(final CodeRunner ctxt,
                                                            final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return c.isReadOnly() ? Value.TRUE : Value.FALSE;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_is_read_only(CodeRunner, Value)'

    /**
     * Tests whether the passed connection is still valid.
     * @param ctxt context
     * @param connection connection
     * @param timeout timeout
     * @return <tt>true</tt> if the connection is still valid,
     *         <tt>false</tt> otherwise
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_is_valid(final CodeRunner ctxt,
                                                        final Value connection,
                                                        final Value timeout)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return c.isValid(timeout.asBlock().asInt32())
                ? Value.TRUE
                : Value.FALSE;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_is_valid(CodeRunner, Value, Value)'

    /**
     * Converts the passed SQL statement into the SQL dialect used by the connection.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @return the passed SQL statement into the SQL dialect used by the connection
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_native_sql(final CodeRunner ctxt,
                                                          final Value connection,
                                                          final Value sql)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            final Block res = Block.createString(c.nativeSQL(sql.asBlock().asString()));
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_native_sql(CodeRunner, Value, Value)'

    /**
     * Creates a statement used to call stored procedures.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @return a statement used to call stored procedures
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_prepare_call(final CodeRunner ctxt,
                                                            final Value connection,
                                                            final Value sql)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.prepareCall(sql.asBlock().asString()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_prepare_call(CodeRunner, Value, Value)'

    /**
     * Creates a statement used to call stored procedures.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @param type result set type
     * @param conc result set concurrency
     * @return a statement used to call stored procedures
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_prepare_call_type_conc(final CodeRunner ctxt,
                                                                      final Value connection,
                                                                      final Value sql,
                                                                      final Value type,
                                                                      final Value conc)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.prepareCall(sql.asBlock().asString(),
                                                      Misc.decodeResultSetType(type),
                                                      Misc.decodeResultSetConcurrency(conc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_prepare_call_type_conc(CodeRunner, Value, Value, Value, Value)'

    /**
     * Creates a statement used to call stored procedures.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @param type result set type
     * @param conc result set concurrency
     * @param hold result set holdability
     * @return a statement used to call stored procedures
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_prepare_call_type_conc_hold(final CodeRunner ctxt,
                                                                           final Value connection,
                                                                           final Value sql,
                                                                           final Value type,
                                                                           final Value conc,
                                                                           final Value hold)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.prepareCall(sql.asBlock().asString(),
                                                      Misc.decodeResultSetType(type),
                                                      Misc.decodeResultSetConcurrency(conc),
                                                      Misc.decodeResultSetHoldability(hold)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_prepare_call_type_conc_hold(CodeRunner, Value, Value, Value, Value, Value)'

    /**
     * Creates a statement used to retrieve autogen keys.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @return a statement used to call stored procedures
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_prepare_statement(final CodeRunner ctxt,
                                                                 final Value connection,
                                                                 final Value sql)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.prepareStatement(sql.asBlock().asString()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_prepare_statement(CodeRunner, Value, Value)'

    /**
     * Creates a statement used to retrieve auto generated keys.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @param autogenKeys auto generated keys option
     * @return a statement used to call stored procedures
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_prepare_statement_autogen_keys(final CodeRunner ctxt,
                                                                              final Value connection,
                                                                              final Value sql,
                                                                              final Value autogenKeys)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.prepareStatement(sql.asBlock().asString(),
                                                           Misc.decodeStatementAutogenKeys(autogenKeys)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_prepare_statement_autogen_keys(CodeRunner, Value, Value, Value)'

    /**
     * Creates a statement used to retrieve auto generated keys.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @param indexes indexes of columns that should be returned
     * @return a statement used to call stored procedures
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_prepare_statement_indexes(final CodeRunner ctxt,
                                                                         final Value connection,
                                                                         final Value sql,
                                                                         final Value indexes)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            final List<Integer> columns = new ArrayList<Integer>();
            Value list = indexes;
            while (list != Value.EMPTY_LIST) {
                final Block b = list.asBlock();
                columns.add(b.get(0).asLong());
                list = b.get(1);
            } // end while
            final int[] cols = new int[columns.size()];
            int i = 0;
            for (Integer ii : columns) {
                cols[i++] = ii;
            } // end for
            return Cadmium.createObject(c.prepareStatement(sql.asBlock().asString(),
                                                           cols));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_prepare_statement_indexes(CodeRunner, Value, Value, Value)'

    /**
     * Creates a statement used to retrieve auto generated keys.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @param type result set type
     * @param conc result set concurrency
     * @return a statement used to call stored procedures
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_prepare_statement_type_conc(final CodeRunner ctxt,
                                                                           final Value connection,
                                                                           final Value sql,
                                                                           final Value type,
                                                                           final Value conc)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.prepareStatement(sql.asBlock().asString(),
                                                           Misc.decodeResultSetType(type),
                                                           Misc.decodeResultSetConcurrency(conc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_prepare_statement_type_conc(CodeRunner, Value, Value, Value, Value)'

    /**
     * Creates a statement used to retrieve auto generated keys.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @param type result set type
     * @param conc result set concurrency
     * @param hold result set holdability
     * @return a statement used to call stored procedures
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_prepare_statement_type_conc_hold(final CodeRunner ctxt,
                                                                                final Value connection,
                                                                                final Value sql,
                                                                                final Value type,
                                                                                final Value conc,
                                                                                final Value hold)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.prepareStatement(sql.asBlock().asString(),
                                                           Misc.decodeResultSetType(type),
                                                           Misc.decodeResultSetConcurrency(conc),
                                                           Misc.decodeResultSetHoldability(hold)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_prepare_statement_type_conc_hold(CodeRunner, Value, Value, Value, Value, Value)'

    /**
     * Creates a statement used to retrieve auto generated keys.
     * @param ctxt context
     * @param connection connection
     * @param sql SQL statement
     * @param names names of columns that should be returned
     * @return a statement used to call stored procedures
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
   public static Value cadmiumjdbc_connection_prepare_statement_names(final CodeRunner ctxt,
                                                                      final Value connection,
                                                                      final Value sql,
                                                                      final Value names)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            final List<String> columns = new ArrayList<String>();
            Value list = names;
            while (list != Value.EMPTY_LIST) {
                final Block b = list.asBlock();
                columns.add(b.get(0).asBlock().asString());
                list = b.get(1);
            } // end while
            return Cadmium.createObject(c.prepareStatement(sql.asBlock().asString(),
                                                           columns.toArray(new String[columns.size()])));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_prepare_statement_names(CodeRunner, Value, Value, Value)'

    /**
     * Release a given savepoint for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param savepoint savepoint
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_release_savepoint(final CodeRunner ctxt,
                                                                 final Value connection,
                                                                 final Value savepoint)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.releaseSavepoint((Savepoint) savepoint.asBlock().asCustom());
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_release_savepoint(CodeRunner, Value, Value)'

    /**
     * Cancels the changes for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_rollback(final CodeRunner ctxt,
                                                        final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.rollback();
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_rollback(CodeRunner, Value)'

    /**
     * Reverts to the state as defined by a given savepoint for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param savepoint savepoint
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_rollback_to(final CodeRunner ctxt,
                                                           final Value connection,
                                                           final Value savepoint)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.rollback((Savepoint) savepoint.asBlock().asCustom());
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_rollback_to(CodeRunner, Value, Value)'

    /**
     * Sets the value of the 'autocommit' property for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param v new value
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_set_auto_commit(final CodeRunner ctxt,
                                                               final Value connection,
                                                               final Value v)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.setAutoCommit(v == Value.TRUE);
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_set_auto_commit(CodeRunner, Value, Value)'

    /**
     * Sets the value of the 'catalog' property for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param v new value
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_set_catalog(final CodeRunner ctxt,
                                                           final Value connection,
                                                           final Value v)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.setCatalog(v.asBlock().asString());
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_set_catalog(CodeRunner, Value, Value)'

    /**
     * Sets the client info properties the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param v new value
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_set_client_infos(final CodeRunner ctxt,
                                                                final Value connection,
                                                                final Value v)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.setClientInfo(Misc.decodeProperties(v));
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_set_client_infos(CodeRunner, Value, Value)'

    /**
     * Sets a client info property the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param n property name
     * @param v new value
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_set_client_info(final CodeRunner ctxt,
                                                               final Value connection,
                                                               final Value n,
                                                               final Value v)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.setClientInfo(n.asBlock().asString(), v.asBlock().asString());
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_set_client_info(CodeRunner, Value, Value, Value)'

    /**
     * Sets the value of the 'holdability' property for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param v new value
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_set_holdability(final CodeRunner ctxt,
                                                               final Value connection,
                                                               final Value v)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.setHoldability(Misc.decodeResultSetHoldability(v));
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_set_holdability(CodeRunner, Value, Value)'

    /**
     * Sets the value of the 'read-only' property for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param v new value
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_set_read_only(final CodeRunner ctxt,
                                                             final Value connection,
                                                             final Value v)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.setReadOnly(v == Value.TRUE);
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_set_read_only(CodeRunner, Value, Value)'

    /**
     * Creates an unnamed savepoint for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @return a new savepoint
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_set_savepoint(final CodeRunner ctxt,
                                                             final Value connection)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.setSavepoint());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_set_savepoint(CodeRunner, Value)'

    /**
     * Creates a named savepoint for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param name savepoint name
     * @return a new savepoint
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_set_savepoint_with_name(final CodeRunner ctxt,
                                                                       final Value connection,
                                                                       final Value name)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            return Cadmium.createObject(c.setSavepoint(name.asBlock().asString()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_set_savepoint_with_name(CodeRunner, Value, Value)'

    /**
     * Sets the value of the 'transaction isolation' property for the passed connection.
     * @param ctxt context
     * @param connection connection
     * @param v new value
     * @return <i>unit</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiumjdbc_connection_set_transaction_isolation(final CodeRunner ctxt,
                                                                         final Value connection,
                                                                         final Value v)
        throws Fail.Exception {
        try {
            final Connection c = (Connection) connection.asBlock().asCustom();
            c.setTransactionIsolation(Misc.decodeTransactionIsolation(v));
            return Value.UNIT;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiumjdbc_connection_set_transaction_isolation(CodeRunner, Value, Value)'

} // end class 'Connections'
